﻿using Plugin.BLE;
using Plugin.BLE.Abstractions;
using Plugin.BLE.Abstractions.Contracts;
using Plugin.BLE.Abstractions.EventArgs;
using System.Diagnostics;
using System.Text;

namespace MaBlaApp.Data;

/// <summary>
/// 低功耗蓝牙测试者
/// </summary>
public class BleTester
{
    private IBluetoothLE CurrentBle;
    private IAdapter CurrentAdapter;

    private CancellationTokenSource _scanForAedCts;

    public BleTester()
    {
        CurrentBle = CrossBluetoothLE.Current;
        CurrentAdapter = CrossBluetoothLE.Current.Adapter;

        CurrentBle.StateChanged += Ble_StateChanged;

        CurrentAdapter.DeviceConnected += Adapter_DeviceConnected;
        CurrentAdapter.DeviceDisconnected += Adapter_DeviceDisconnected;
    }

    #region BLE状态管理

    private void Ble_StateChanged(object sender, BluetoothStateChangedArgs e)
    {
        Debug.WriteLine($"蓝牙状态改变为{e.NewState}");
    }

    private void Adapter_DeviceConnected(object sender, DeviceEventArgs e)
    {
        Debug.WriteLine($"连接成功{e.Device.Name}");
    }

    private void Adapter_DeviceDisconnected(object sender, DeviceEventArgs e)
    {
        Debug.WriteLine($"断开连接{e.Device.Name}");
    }

    #endregion

    #region 扫描外设

    /// <summary>
    /// 开始扫描
    /// </summary>
    /// <returns></returns>
    public async Task<bool> StartScanAsync()
    {
        //检查获取蓝牙权限
        bool isPermissionPass = await CheckAndRequestBluetoothPermission();
        if (!isPermissionPass)
            return false;

        _scanForAedCts = new CancellationTokenSource();

        try
        {
            CurrentAdapter.DeviceDiscovered += Adapter_DeviceDiscovered;
            CurrentAdapter.ScanTimeoutElapsed += Adapter_ScanTimeoutElapsed;

            //蓝牙扫描时间
            CurrentAdapter.ScanTimeout = 10 * 1000;

            //默认LowPower
            CurrentAdapter.ScanMode = ScanMode.LowPower;

            Debug.WriteLine($"开始扫描外设, IsAvailable={CurrentBle.IsAvailable}, IsOn={CurrentBle.IsOn}, State={CurrentBle.State}, ScanMode={CurrentAdapter.ScanMode}, ScanTimeout={CurrentAdapter.ScanTimeout}");

            await CurrentAdapter.StartScanningForDevicesAsync(cancellationToken: _scanForAedCts.Token);

            Debug.WriteLine($"结束扫描外设");
        }
        catch (OperationCanceledException)
        {
            Debug.WriteLine($"扫描外设任务取消");
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"扫描外设出错, {ex.Message}");
        }
        finally
        {
            CurrentAdapter.DeviceDiscovered -= Adapter_DeviceDiscovered;
            CurrentAdapter.ScanTimeoutElapsed -= Adapter_ScanTimeoutElapsed;
        }

        return true;
    }

    /// <summary>
    /// 检查获取蓝牙权限
    /// </summary>
    /// <returns></returns>
    public async Task<bool> CheckAndRequestBluetoothPermission()
    {
#if ANDROID

        var status = await Permissions.CheckStatusAsync<BluetoothPermissions>();

        if (status == PermissionStatus.Granted)
            return true;

        status = await Permissions.RequestAsync<BluetoothPermissions>();

        if (status == PermissionStatus.Granted)
            return true;

#endif

        return true;
    }

    public string TagDeviceName { get; set; } = "";

    public IDevice Device = null;

    public string TagDeviceInfo { get; private set; } = "";

    private void Adapter_DeviceDiscovered(object sender, DeviceEventArgs e)
    {
        //[0:] 扫描到蓝牙设备honor Band 4-7E8, Id=00000000-0000-0000-0000-f4bf805ad7e8, Name=honor Band 4-7E8, Rssi=-50, State=Disconnected, AdvertisementRecords.Count=5
        Debug.WriteLine($"扫描到蓝牙设备{e.Device}, Id={e.Device.Id}, Name={e.Device.Name}, Rssi={e.Device.Rssi}, State={e.Device.State}, AdvertisementRecords.Count={e.Device.AdvertisementRecords.Count}");

        string localName = e.Device.Name;

        if (string.Compare(localName, TagDeviceName, true) == 0)
        {
            TagDeviceInfo = $"{e.Device}, Id={e.Device.Id}, Name={e.Device.Name}, Rssi={e.Device.Rssi}, State={e.Device.State}, AdvertisementRecords.Count={e.Device.AdvertisementRecords.Count}";

            Device = e.Device;

            //如果找到目标外设，退出扫描
            if (!_scanForAedCts.IsCancellationRequested)
                _scanForAedCts.Cancel(false);
        }
    }

    private void Adapter_ScanTimeoutElapsed(object sender, EventArgs e)
    {
        Debug.WriteLine("蓝牙扫描超时结束");
    }

    #endregion

    #region 连接外设

    //连接蓝牙外设
    public async Task<bool> ConnectDeviceAsync()
    {
        Debug.WriteLine($"开始连接{TagDeviceName}");

        //连接外设
        //设置forceBleTransport=true, 否则错误GattCallback error: 133
        //这个是函数只发起连接，不代表连接成功
        await CurrentAdapter.ConnectToDeviceAsync(Device, new ConnectParameters(false, true));

        //订阅连接丢失
        CurrentAdapter.DeviceDisconnected += CurrentAdapter_DeviceDisconnected;

        //订阅连接断开
        CurrentAdapter.DeviceConnectionLost += CurrentAdapter_DeviceConnectionLost;

        Debug.WriteLine($"连接成功{TagDeviceName}");

        return true;
    }

    //订阅连接丢失
    private void CurrentAdapter_DeviceConnectionLost(object? sender, DeviceErrorEventArgs e)
    {
        Debug.WriteLine($"蓝牙连接丢失, {e.Device?.State}");

        CurrentAdapter.DeviceConnectionLost -= CurrentAdapter_DeviceConnectionLost;
        CurrentAdapter.DeviceDisconnected -= CurrentAdapter_DeviceDisconnected;
    }

    //订阅连接断开
    private void CurrentAdapter_DeviceDisconnected(object? sender, DeviceEventArgs e)
    {
        Debug.WriteLine($"蓝牙连接状态变化, {e.Device?.State}");

        CurrentAdapter.DeviceConnectionLost -= CurrentAdapter_DeviceConnectionLost;
        CurrentAdapter.DeviceDisconnected -= CurrentAdapter_DeviceDisconnected;
    }

    #endregion

    #region 读写数据

    public string ReadDeviceNameResult { get; private set; } = "未读取";

    //读取设备名
    public async Task<bool> ReadDeviceName()
    {
        ReadDeviceNameResult = "未读取";

        Debug.WriteLine($"开始获取服务");

        //获取服务集合
        var services = await Device.GetServicesAsync();
        var infoes = services.Select(x => $"{x.Id}: Name={x.Name}, IsPrimary={x.IsPrimary}");
        string msg = $"服务Uuid: " + string.Join(", ", infoes);
        Debug.WriteLine(msg);

        //获取常规信息服务
        Guid genericServiceGuid = Guid.Parse("00001800-0000-1000-8000-00805f9b34fb");
        var genericService = await Device.GetServiceAsync(genericServiceGuid);
        if (genericService == null)
        {
            Debug.WriteLine($"获取常规信息服务{genericServiceGuid}失败");
            return false;
        }

        Debug.WriteLine($"开始获取特征值");

        //获取特征值集合
        var characteristics = await genericService.GetCharacteristicsAsync();
        infoes = characteristics.Select(x => $"{x.Id}: {x.Properties}");
        msg = $"特征值: " + string.Join(", ", infoes);
        Debug.WriteLine(msg);

        //获取设备名特征值
        Guid deviceNameCharacteristicGuid = Guid.Parse("00002a00-0000-1000-8000-00805f9b34fb");
        var deviceNameCharacteristic = characteristics.FirstOrDefault(x => x.Id == deviceNameCharacteristicGuid);
        if (deviceNameCharacteristic == null)
        {
            Debug.WriteLine($"获取设备名特征值{deviceNameCharacteristicGuid}失败");
            return false;
        }

        //读取设备名特征值
        var ary = await ReadDataAsync(deviceNameCharacteristic);

        if (ary is not null)
        {
            ReadDeviceNameResult = Encoding.ASCII.GetString(ary);
        }

        #region notify类型特征值接收消息通知

        //notifyCharacteristic.ValueUpdated += NotifyCharacteristic_ValueUpdated;

        #endregion

        return true;
    }

    //读特征值
    private async Task<byte[]> ReadDataAsync(ICharacteristic characteristic)
    {
        //根据Plugin.BLE要求，在主线程读写数据
        var result = await MainThread.InvokeOnMainThreadAsync(async () =>
        {
            try
            {
                //读取数据
                byte[] ary = await characteristic.ReadAsync();

                Debug.WriteLine($"读取成功，长度={ary.Length}");

                return ary;
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"读取错误, 目标设备蓝牙连接状态={Device?.State}, {ex.Message}");

                return null;
            }
        });

        return result;
    }

    //写特征值
    public async Task<bool> SendDataAsync(ICharacteristic characteristic, byte[] ary)
    {
        //根据Plugin.BLE要求，在主线程发送数据
        bool success = await MainThread.InvokeOnMainThreadAsync(async () =>
        {
            try
            {
                //写入数据
                bool writeSuccess = await characteristic.WriteAsync(ary);

                Debug.WriteLine($"写入结果={writeSuccess}，长度={ary.Length}");

                return writeSuccess;
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"写入错误, 目标设备蓝牙连接状态={Device?.State}, {ex.Message}");

                return false;
            }
        });

        return success;
    }

    private void NotifyCharacteristic_ValueUpdated(object sender, CharacteristicUpdatedEventArgs e)
    {
        byte[] ary = e.Characteristic.Value;

        string msg = $"{DateTime.Now}, 收到特征值更新事件, 特征值={e.Characteristic.Id}, 数据包长度={ary?.Length}";
        Debug.WriteLine(msg);
    }

    #endregion

}
